/*
 * Copyright (c) 2006-2021, RT-Thread Development Team
 *
 * SPDX-License-Identifier: Apache-2.0
 *
 * Change Logs:
 * Date           Author       Notes
 * 2021-06-29     wyjhotice       the first version
 */
#ifndef APPLICATIONS_AM2305_AM2305_C_
#define APPLICATIONS_AM2305_AM2305_C_

#define LOG_TAG                        "am2305"
#define DBG_LVL                         DBG_LOG
#include <rtdbg.h>

#include <rtthread.h>
#include <rtdevice.h>
#include <board.h>

#include "am2305/am2305.h"

#define CONNECT_SUCCESS  0
#define CONNECT_FAILED   1

static am2305_dev am2305_temp[AM2305_DEV_NUM];
rt_thread_t am2305_run_tid;

static uint8_t am2305_running = 0;
RT_WEAK void rt_hw_us_delay(rt_uint32_t us)
{
    rt_uint32_t delta;

    us = us * (SysTick->LOAD / (1000000 / RT_TICK_PER_SECOND));
    delta = SysTick->VAL;

    while (delta - SysTick->VAL < us)
        continue;
}

static void am2305_reset(rt_base_t pin)
{
    rt_pin_mode(pin, PIN_MODE_OUTPUT);
    rt_pin_write(pin, PIN_LOW);
    rt_thread_mdelay(1);
    rt_pin_write(pin, PIN_HIGH);
    rt_hw_us_delay(40); /* 15us - 60us*/
}

static uint8_t am2305_connect(rt_base_t pin)
{
    uint8_t retry = 0;
    rt_pin_mode(pin, PIN_MODE_INPUT);

    while (rt_pin_read(pin) && retry < 200)
    {
        retry++;
        rt_hw_us_delay(1);
    };

    if (retry >= 200)
        return CONNECT_FAILED;
    else
        retry = 0;

    while (!rt_pin_read(pin) && retry < 240)
    {
        retry++;
        rt_hw_us_delay(1);
    };

    if (retry >= 240)
        return CONNECT_FAILED;

    return CONNECT_SUCCESS;
}

static uint8_t am2305_read_bit(rt_base_t pin)
{

    uint8_t retry = 0;
    uint8_t data;
    while (rt_pin_read(pin) && retry < 80) //等待变为低电平
    {
        retry++;
        rt_hw_us_delay(1);
    }
    if (retry >= 80)
    {
        data = 0x80;
        return data;
    }
    retry = 0;
    while (!rt_pin_read(pin) && retry < 60) //等待变高电平
    {
        retry++;
        rt_hw_us_delay(1);
    }
    if (retry >= 60)
    {
        data = 0x80;
        return data;
    }

    rt_hw_us_delay(38);
    if (rt_pin_read(pin))
        data = 1;
    else
        data = 0;
    return data;
}

static uint8_t am2305_read_byte(rt_base_t pin)
{
    uint8_t i, j, dat;
    dat = 0;

    for (i = 1; i <= 8; i++)
    {
        j = am2305_read_bit(pin);
        if (j & 0x80)
        {
            dat = 0xff;
            break;
        }
        else
            dat = j | (dat << 1);
    }

    return dat;
}

/*************************************************************************************************************************
 *函数         :   bool am2305_read_data(am2305_dev am2305)
 *功能         :   从AM2305读取一次数据
 *参数         :   am2305:输入2305设备结构体
 *返回         :   FALSE:读取失败;TRUE:读取成功
 *说明         :   2021-06-29:编写
 *************************************************************************************************************************/
uint8_t am2305_read_data(am2305_dev *am2305)
{
    uint8_t buf[5];
    uint8_t i;
    uint16_t utemp=0, uhumi=0;
    uint16_t ptemp=0;
    am2305_reset(am2305->data_pin);
    if (am2305_connect(am2305->data_pin) == CONNECT_SUCCESS)
    {
        for (i = 0; i < 5; i++) //读取40位数据
        {
            buf[i] = am2305_read_byte(am2305->data_pin);
        }
        if ((uint8_t) (buf[0] + buf[1] + buf[2] + buf[3]) == buf[4])
        {
            uhumi = buf[0];
            uhumi <<= 8;
            uhumi |= buf[1];
            am2305->humi = uhumi;
            utemp = buf[2];
            utemp <<= 8;
            utemp |= buf[3];
            if (utemp > 0x8000)
            {
                utemp -= 0x8000;
                ptemp = 0 - utemp;
            }
            else
            {
                ptemp = utemp;
            }
            am2305->temp = ptemp;
            return 0;
        }
        else
        {
            LOG_W("AM2305 data check failed!!!");
            return 1;
        }
    }
    else
    {
        LOG_W("AM2305 detect failed!!!");
        return 1;
    }
}

static void am2305_get_temp_humi(void *parameter)
{
    uint8_t i;
    rt_thread_mdelay(3500);                 //延迟等待设备稳定
    am2305_running = 1;
    while(am2305_running)
    {
        for(i = 0; i<AM2305_DEV_NUM;i++)
        {
            am2305_read_data(&am2305_temp[i]);
            rt_thread_mdelay(1);
            LOG_D("temp:%d,humi:%d",am2305_temp[i].temp,am2305_temp[i].humi);
        }

//        rt_thread_mdelay(2000);
//        for(i = 0; i<AM2305_DEV_NUM;i++)
//                {
//                    am2305_read_data(am2305_temp[0]);
//                    rt_thread_mdelay(1);
//                }
        rt_thread_mdelay(AM2305_READ_INTV*1000);
    }

}
/*********************************************************************************************
 * 此函数用于给所有的2305设备指定data——pin，若有多个此设备，需要将其全部初始化
 *
 *********************************************************************************************/
void am2305_init(void)
{
    am2305_temp[0].data_pin = AM2305_DATA0_PIN;
    am2305_temp[0].humi = 0;
    am2305_temp[0].temp = 0;
}
/*********************************************************************************************
 * 此函数用于建立2305的读取线程，
 *
 *********************************************************************************************/
void am2305_start(void)
{
    am2305_init();
    am2305_run_tid = rt_thread_create("am2305 run", am2305_get_temp_humi, RT_NULL, 1024, 8, 20);
    /* 创建成功则启动线程 */
    if (am2305_run_tid != RT_NULL)
    {
        rt_thread_startup(am2305_run_tid);
    }
    else
    {
        LOG_E("am2305 run create failed!");
    }
}
MSH_CMD_EXPORT(am2305_start, am2305 start);



#endif /* APPLICATIONS_AM2305_AM2305_C_ */
